package org.dei.dataserver;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Prima versione del server di comunicazione con la scheda intec
 * 
 * @author Guido Rota
 */
public class Receiver {
        
        static ServerSocket serverSocket = null;
        
        public static final char SEND_COMMAND = 's';
        public static final char UPDATE_COMMAND = 'p';
        public static final char ACK = 'a';
        public static final byte DEV_NUMBER = 4;
        public static final String BASE_FILE_NAME = "./mem_id_";
        public static final String FILE_EXTENSION = ".dat";
        
        private static void acceptConnection() {
                
                Socket clientSocket = null;
                DataInputStream dIn = null;
                DataOutputStream dOut = null;
                
                try {
                        System.out.println("Accepting...");
                        clientSocket = serverSocket.accept();
                        System.out.println("Connection accepted!");
                } catch (IOException e) {
                        System.out.println("Error accepting incoming connection!");
                        e.printStackTrace();
                }
                
                try {
                        dIn = new DataInputStream(clientSocket.getInputStream());
                        dOut = new DataOutputStream(clientSocket.getOutputStream());
                } catch (IOException e) {
                        System.out.println("Error setting input and output streams!");
                        e.printStackTrace();
                }
                
                try {
                        char command = (char)dIn.read();
                        
                        if (command == SEND_COMMAND) {
                                System.out.println("Send command received!");
                                receiveMessage(dIn, dOut);
                                clientSocket.close();
                        } else if (command == UPDATE_COMMAND) {
                                System.out.println("Update command received!");
                                sendUpdate(dIn, dOut);
                                clientSocket.close();
                        }
                } catch (IOException e) {
                        System.out.println("Error executing the command!");
                        e.printStackTrace();
                }
        }
        
        private static void receiveMessage(DataInputStream dIn, DataOutputStream dOut) {
                 byte fileNumber = 0;
                 long fileSize = 0;
                 FileOutputStream fOut;
                 File file;
                
                try {
                        fileNumber = (byte)dIn.read();
                        fileSize += (dIn.read() & 0xFF) << 0;
                        fileSize += (dIn.read() & 0xFF) << 8;
                        fileSize += (dIn.read() & 0xFF) << 16;
                        fileSize += (dIn.read() & 0xFF) << 24;
                        System.out.println("Preparing to receive the file number " + fileNumber + ", of size " + fileSize);
                        System.out.println("Sending ACK...");
                        dOut.write((byte)ACK);
                        file = new File(BASE_FILE_NAME + fileNumber + FILE_EXTENSION);
                        fOut = new FileOutputStream(file);
                        
                        System.out.println("Writing to file...");
                        while (fileSize != 0) {
                                fOut.write(dIn.read());
                                fileSize--;
                        }
                        fOut.close();
                        System.out.println("Writing done!");
                        
                } catch (IOException e) {
                        System.out.println("Error reading the file or the file specs!");
                        e.printStackTrace();
                }
        }
        
        private static void sendUpdate(DataInputStream dIn, DataOutputStream dOut) {
                String update = "update";
                long updateLen = update.length();
                try {
                        System.out.println("Sending the number of devices to update...");
                        dOut.write((byte)DEV_NUMBER);
                        if (dIn.read() != ACK) {
                                return;
                        }
                        System.out.println("ACK received!");
                        for (int i = 0; i < DEV_NUMBER; i++) {
                                System.out.println("Sending update for device " + i);
                                dOut.write(i & 0xFF);
                                dOut.write((byte)(updateLen & 0xFF));
                                dOut.write((byte)((updateLen >>> 8) & 0xFF));
                                dOut.write((byte)((updateLen >>> 16) & 0xFF));
                                dOut.write((byte)((updateLen >>> 24) & 0xFF));
                                if (dIn.read() != ACK) {
                                        return;
                                }
                                System.out.println("ACK received!");
                                for (int j = 0; j < updateLen; j++) {
                                        dOut.write((byte)update.charAt(j));
                                }
                                if (dIn.read() != ACK) {
                                        return;
                                }
                        }
                        
                } catch (IOException e) {
                        System.out.println("Error updating the parameters!");
                        e.printStackTrace();
                }
        }
        
        public static void main(String[] args)  {
                
                InetSocketAddress sockAddr;
                
                sockAddr = new InetSocketAddress(5606);
                
                try {
                        serverSocket = new ServerSocket();
                        serverSocket.setReuseAddress(true);
                        serverSocket.bind(sockAddr);
                } catch (IOException e) {
                        System.out.println("Error listening on port 5606!");
                        e.printStackTrace();
                        System.exit(1);
                }
                
                while(true) {
                        acceptConnection();
                }
        }
}
